﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class playerScript : MonoBehaviour {

    //game objects
    public GameObject bullet;
    public GameObject muzzleFlash;
    private GameObject playerHolder;
    public GameObject controller;
    private Collider2D cover;
    private Collider2D enemy;
    private Rigidbody2D rbod;
    private List<GameObject> enemies;
    //player variables
    public float health;
    private float startHealth;
    public float bulletSpeed;
    private float reloadTime;
    private float dodgeSpeed;
    public float[,] weapons;
    private float[,] startWeapons;
    public int[] ammo;
    private int[] startAmmo;
    public int[] playerSkillLevel;
    private int[] startPlayerSkillLevel;
    public int[] playerStats;
    private int[] startPlayerStats;
    public float[,] skillTable;
    public int equippedWeapon;
    private int startEquippedWeapon;
    private float dodgeCooldown;
    private Vector2 direction;
    private float shotCooldown;
    private Vector3 startPos;
    private Quaternion startRot;
    //player states
    public bool playerHit=false;	
	public bool colliding;
	public bool inCover;
	private bool canCover;
	private bool isDodging;
	private bool isReloading;	
	private bool dodgeCooled = true;	
    private bool canTakedown;    
	private bool isCooled;	    

    void Start(){
        //initialize variables        
        playerStats = new int[] { 1, 0 };
        playerHolder = GameObject.FindGameObjectWithTag("playerHolder");
		rbod = GetComponent<Rigidbody2D> ();
		weapons = new float[,] { { 1f, 8f, 8f, 0.9f, 1.5f, 0.35f, 1f },
			{ 2f, 5f, 5f, 0.65f, 2.5f, 1.2f, 2f }
		};
		ammo = new int[]{ 15, 15, 15, 15, 15, 15 };
		equippedWeapon = 1;
		dodgeCooldown = 0.21f;
		dodgeSpeed = 30;
		//build the skill table array
		skillTable = new float[,] { { 1, 1.25f, 1.5f, 1.75f, 2 },
			{ 1, 1.25f, 1.5f, 1.75f, 2 },
			{ 10, 15, 20, 25, 30 },
			{ 3, 3.25f, 3.5f, 3.75f, 4.25f },
			{ 3, 4, 5, 7, 9 }
		};

        // assign player skills by reading from playerHolder array
        playerSkillLevel = playerHolder.GetComponent<basePlayer>().playerSkillLevels;
		health = skillTable [2, playerSkillLevel [2]-1];
        

        //assign starting variables for beginning checkpoint
        enemies = new List<GameObject>();
        startPos = gameObject.transform.position;
        startRot = gameObject.transform.rotation;
        startHealth = health;
        startEquippedWeapon = equippedWeapon;
        startAmmo = new int [ammo.Length];
        Array.Copy(ammo, startAmmo, ammo.Length);    
        startPlayerSkillLevel = new int[playerSkillLevel.Length];
        Array.Copy(playerSkillLevel, startPlayerSkillLevel, playerSkillLevel.Length);        
        startPlayerStats = new int[playerStats.Length];
        Array.Copy(playerStats, startPlayerStats, playerStats.Length);
        startWeapons = new float[2, weapons.Length];
        Array.Copy(weapons, startWeapons, weapons.LongLength);

    }
	void FixedUpdate(){
		if (isDodging) {			
			if (dodgeCooled) {
				//get current direction the player is moving at time this is first called
				direction = new Vector2 (Input.GetAxisRaw ("Horizontal"), Input.GetAxisRaw ("Vertical"));
				//if the player is moving they can dodge
				if (direction.x != 0 || direction.y != 0) {
					//multiply the direction x and y by dodgeSpeed to set their force
					direction.x = direction.x * dodgeSpeed;
					direction.y = direction.y * dodgeSpeed;
				}
				//set dodgeCooled to false so this is only called once
				dodgeCooled = false;
			}
			if (dodgeCooldown > 0) {
				//add force over time to smooth it out
				rbod.AddForce (direction, ForceMode2D.Impulse);
				dodgeCooldown -= Time.deltaTime;
			} else {
				//cleanup after dodge has taken place
				isDodging = false;
				dodgeCooldown = 0.21f;
				dodgeCooled = true;
                rbod.velocity = new Vector2(0, 0);

			}
		}
	}
	void Update() {       
		//check if player is dead
		if (health <= 0) {
			resetPlayer();
		}

		//subtract from shotcooldown
		if (shotCooldown > 0) {
			shotCooldown -= Time.deltaTime;
		} else {
			isCooled = true;
		}

		//check if player is reloading
		if (isReloading) {
			//quit reloading if you are out of needed ammo type or your gun is already loaded to max
			if (ammo [System.Convert.ToInt32 (weapons [equippedWeapon - 1, 6]) - 1] == 0 || weapons[equippedWeapon-1, 1] == weapons[equippedWeapon-1,2])
				isReloading = false;
			//if reload time has elapsed, reload the current weapon
			if (reloadTime <= 0) {
				if (ammo [System.Convert.ToInt32 (weapons [equippedWeapon - 1, 6]) - 1] < (weapons [equippedWeapon - 1, 1]) - weapons [equippedWeapon-1, 2]) {
					weapons [equippedWeapon - 1, 2] += ammo [System.Convert.ToInt32 (weapons [equippedWeapon - 1, 6]) - 1];
					ammo [System.Convert.ToInt32 (weapons [equippedWeapon - 1, 6]) - 1] -= ammo [System.Convert.ToInt32 (weapons [equippedWeapon - 1, 6]) - 1];
					isReloading = false;
				} else {					
					ammo [System.Convert.ToInt32 (weapons [equippedWeapon - 1, 6]) - 1] -= System.Convert.ToInt32 (weapons [equippedWeapon - 1, 1] - weapons [equippedWeapon-1, 2]);
					weapons [equippedWeapon - 1, 2] = weapons [equippedWeapon - 1, 1];
					isReloading = false;
				}
			}
			reloadTime -= Time.deltaTime * skillTable[1, playerSkillLevel[1]-1];            
		}

		//check if cover has been destroyed
		if (cover == null) {
			inCover = false;
			canCover = false;
		}

		//rotate player towards mouse
		if (!inCover) {
			Vector3 mousePos = Input.mousePosition;
			mousePos.z = 5.23f;
			Vector3 objectPos = Camera.main.WorldToScreenPoint (transform.position);
			mousePos.x = mousePos.x - objectPos.x;
			mousePos.y = mousePos.y - objectPos.y;
			float angle = Mathf.Atan2 (mousePos.y, mousePos.x) * Mathf.Rad2Deg;
			transform.rotation = Quaternion.Euler (new Vector3 (0, 0, angle));
		}

		//fire weapon if mouse button is clicked and player is not in cover and their weapon has bullets remaining
		if (Input.GetButtonDown ("Fire1") && !inCover && weapons [equippedWeapon - 1, 2] > 0 && !isReloading && !controller.GetComponent<sceneController>().menuOpen) {
			if (isCooled) {
				//get random accurcay jitter
				float randAccX = UnityEngine.Random.Range (-weapons [equippedWeapon - 1, 3], weapons [equippedWeapon - 1, 3]);
				float randAccY = UnityEngine.Random.Range (-weapons [equippedWeapon - 1, 3], weapons [equippedWeapon - 1, 3]);
				Vector2 accuracyJitter = new Vector2 (randAccX / skillTable[0,playerSkillLevel[0]-1], randAccY / skillTable[0,playerSkillLevel[0]-1]);
				//collect target and game object postions
				Vector2 target = Camera.main.ScreenToWorldPoint (new Vector2 (Input.mousePosition.x, Input.mousePosition.y));
				Vector2 myPos = new Vector2 (transform.position.x, transform.position.y);
				Vector2 direction = (target - myPos) + accuracyJitter;
				direction.Normalize ();
				Quaternion rotation = Quaternion.Euler (0, 0, Mathf.Atan2 (direction.y, direction.x) * Mathf.Rad2Deg);
				muzzleFlash.GetComponent<muzzleFlashScript> ().shotFired = true;
				GameObject projectile = (GameObject)Instantiate (bullet, myPos, rotation);
				//checks what weapon is equiped and sets bullets damage
				projectile.GetComponent<bulletBehavior> ().damage = System.Convert.ToInt32 (weapons [equippedWeapon - 1, 0]);
				projectile.GetComponent<Rigidbody2D> ().velocity = direction * bulletSpeed;
				weapons [equippedWeapon - 1, 2]--;
				//starts fire rate cooldown based on equipped weapon
				shotCooldown = weapons[equippedWeapon-1, 5];
				isCooled = false;
			}
		}

		//toggle player in and out of cover
		if (Input.GetButtonDown ("Cover")) {
			if (canCover) {
				if (inCover) {
					cover.GetComponent<sceneObjects> ().providingCover = false;
					inCover = false;
				} else {
					cover.GetComponent<sceneObjects> ().providingCover = true;
					inCover = true;
				}
			}
		}

        //toggle player in and out of cover
        if (Input.GetButtonDown("Takedown"))
        {
            if (!enemy.GetComponent<enemyScript>().isAttacking && canTakedown)
            {
                enemy.GetComponent<enemyScript>().health = 0;
            }
        }

        //open and close the character menu
        if (Input.GetButtonDown("Menu"))
        {
            if (controller.GetComponent<sceneController>().menuOpen)
            {
                controller.GetComponent<sceneController>().closeCharacterMenu();
            }
            else
            {
                controller.GetComponent<sceneController>().openCharacterMenu();
            }
        }

        //swap equipped weapon
        if (Input.GetButtonDown ("Swap Weapon") && !isReloading) {
			if (equippedWeapon == 1) {
				equippedWeapon = 2;
			} else {
				equippedWeapon = 1;
			}
		}

		//bump speed up if player hit dodge button
		if (Input.GetButtonDown ("Dodge") && !isDodging) {
			isDodging = true;
		}

		//reload currently equipped weapon
		if (Input.GetButtonDown ("Reload") && !isReloading) {			
			reloadTime = weapons [equippedWeapon - 1, 4];
			isReloading = true;
		}

		//move player along x and y axis
		Vector2 move = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
		rbod.MovePosition (rbod.position + move * skillTable [3, playerSkillLevel [3]-1] * Time.deltaTime);

	}

	void OnTriggerEnter2D(Collider2D col){
		if (col.tag == "crate") {
			canCover = true;
			cover = col; 
		}
        if (col.tag == "enemy")
        {
            col.GetComponent<enemyScript>().isAlert = true;
            canTakedown = true;
            enemy = col;
        }
        if (col.tag =="checkpoint")
        {
            col.gameObject.SetActive(false);
            reachCheckpoint();
        }
	}
    void OnTriggerExit2D(Collider2D col)
    {
        if (col.tag == "crate")
        {
            //reset bools to false if player moves away from cover
            canCover = false;
            inCover = false;
            col.GetComponent<sceneObjects>().providingCover = false;
        }
        if (col.tag == "enemy")
        {
            col.GetComponent<enemyScript>().isAlert = false;
            canTakedown = false;
        }
    }

    void resetPlayer()
    {
        //reset health and position
        health = startHealth;
        gameObject.transform.position = startPos;
        gameObject.transform.rotation = startRot;

        //reset weapon, ammo, skills, and other arrays back to point of checkpoint
        equippedWeapon = startEquippedWeapon;        
        Array.Copy(startAmmo, ammo, startAmmo.Length);   
        Array.Copy(startPlayerSkillLevel, playerSkillLevel, startPlayerSkillLevel.Length);
        Array.Copy(startPlayerStats, playerStats, startPlayerStats.Length);        
        Array.Copy(startWeapons, weapons, weapons.LongLength);

        //reset player states        
        colliding = false;
        inCover = false;
        canCover = false;
        isDodging = false;
        isReloading = false;
        dodgeCooled = true;
        canTakedown = false;
        isCooled = false;

        //reset enemies 
        //check if the enemies list has anything in it yet
        if (enemies.Count == 0)
        {
            GameObject[] enemyHolder = GameObject.FindGameObjectsWithTag("enemy");
            for (int i = 0; i < enemyHolder.Length; i++)
            {
                enemies.Add(enemyHolder[i]);
            }
        }
        foreach (GameObject go in enemies)
        {
            go.GetComponent<enemyScript>().resetObject();
        }

        //clear other stage elements
        var bloodObj = GameObject.FindGameObjectsWithTag("blood");
        for( int i = 0; i < bloodObj.Length; i++)
        {
            Destroy(bloodObj[i]);
        }
        var dropObj = GameObject.FindGameObjectsWithTag("itemDrop");
        for (int i = 0; i < dropObj.Length; i++)
        {
            Destroy(dropObj[i]);
        }
    }

    public void reachCheckpoint()
    {
        //empty enemies array and then only add enemies that are alive at time check point was hit
        if (enemies.Count > 0)
        {
            enemies.Clear();
        }
        GameObject[] enemyHolder = GameObject.FindGameObjectsWithTag("enemy");
        for (int i=0; i<enemyHolder.Length; i++)
        {
            if(!enemyHolder[i].GetComponent<enemyScript>().isDead)
            {
                enemies.Add(enemyHolder[i]);
            }
        }

        //add player stats to variables 
        startPos = gameObject.transform.position;
        startRot = gameObject.transform.rotation;
        startHealth = health;
        startEquippedWeapon = equippedWeapon;        
        Array.Copy(ammo, startAmmo, ammo.Length);
        Array.Copy(playerSkillLevel, startPlayerSkillLevel, playerSkillLevel.Length);        
        Array.Copy(playerStats, startPlayerStats, playerStats.Length);        
        Array.Copy(weapons, startWeapons, weapons.LongLength);
    }
}
